/************************************************************************
* model_obj.c
* voxelands - 3d voxel world sandbox game
* Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
************************************************************************/

#include "common.h"
#include "graphics.h"

#include <string.h>

struct obj_poly_s {
	GLuint v1;
	GLuint t1;
	GLuint n1;
	GLuint v2;
	GLuint t2;
	GLuint n2;
	GLuint v3;
	GLuint t3;
	GLuint n3;
	mesh_t *m;
};

/* load the materials */
void model_load_obj_mtl(char* file)
{
	file_t* f;
	material_t *m;
	char* data;
	char* p;
	char* e;
	char tmp1[255];
	char name[255];
	float rf;
	float gf;
	float bf;
	float af;
	colour_t c = {255,255,255,255};
	int mkd = 1;

	f = file_load("model",file);
	if (!f)
		return;

	data = (char*)f->data;

	p = data;
	e = data + f->len;

	while (p != e) {
		if (!strncmp(p, "newmtl", 6)) {
			if (!mkd) {
				m = mat_from_colour(&c);
				mat_options(m,MATOPT_ALPHA_BLEND);
				strcpy(m->name,name);
			}
			mkd = 0;
			sscanf(p,"newmtl %s",name);
		}else if (strncmp(p, "map_Kd", 6) == 0) {
			sscanf(p,"map_Kd %s",tmp1);
			m = mat_from_image("texture",tmp1);
			mat_options(m,MATOPT_ALPHA_BLEND);
			mkd = 1;
			strcpy(m->name,name);
		}else if (strncmp(p,"Kd ",3) == 0) {
			sscanf(p,"Kd %f %f %f",&rf,&gf,&bf);
			c.r = (unsigned char)(rf*255.0);
			c.g = (unsigned char)(gf*255.0);
			c.b = (unsigned char)(bf*255.0);
		}else if (strncmp(p,"d ",2) == 0) {
			sscanf(p,"d %f",&af);
			c.a = (unsigned char)(af*255.0);
		}

		p = strchr(p,'\n');
		if (!p)
			break;
		p++;
	}

	if (!mkd) {
		m = mat_from_colour(&c);
		strcpy(m->name,name);
	}
}

/* load an obj model */
model_t *model_load_obj(file_t *f)
{
	char* d;
	model_t* mdl;
	mesh_t *m = NULL;
	material_t *mat;
	char* data;
	char* p;
	char* e;
	v3_t *vert;
	v2_t *tex;
	v3_t *norm;
	struct obj_poly_s *poly;
	int i;
	int nq = 0;
	int tq = 0;
	int vq = 0;
	int pq = 0;
	char tmp[255];
	char file[255];

	d = strrchr(f->name,'.');
	if (!d)
		return NULL;
	*d = 0;
	sprintf(file,"%s.mtl",f->name);
	*d = '.';

	mdl = model_create();

	model_load_obj_mtl(file);

	data = (char*)f->data;
	p = data;
	e = data+f->len;

	while (p < e) {
		if (!strncmp(p, "vn", 2)) {
			nq++;
		}else if (!strncmp(p, "vt", 2)) {
			tq++;
		}else if (!strncmp(p, "v",  1)) {
			vq++;
		}else if (!strncmp(p, "f",  1)) {
			pq++;
		}

		p = strchr(p,'\n');
		if (!p)
			break;
		p++;
	}
	p = data;

	vert = malloc(sizeof(v3_t)*vq);
	if (tq) {
		tex = malloc(sizeof(v2_t)*tq);
	}else{
		tex = malloc(sizeof(v2_t)*2);
		tex[0].x = 0;
		tex[0].y = 0;
		tex[1].x = 1;
		tex[1].y = 1;
	}
	norm = malloc(sizeof(v3_t)*nq);
	poly = malloc(sizeof(struct obj_poly_s)*pq);

	vq = 0;
	nq = 0;
	tq = 0;
	pq = 0;

	/* stage 1, read in the file data */
	while (p < e) {
		if (strncmp(p, "vn", 2) == 0) {
			sscanf(p, "vn %f %f %f", &norm[nq].x, &norm[nq].y, &norm[nq].z);
			nq++;
		}else if (strncmp(p, "vt", 2) == 0) {
			sscanf(p, "vt %f %f", &tex[tq].x, &tex[tq].y);
			tq++;
		}else if (strncmp(p, "v", 1) == 0) {
			sscanf(p, "v %f %f %f", &vert[vq].x, &vert[vq].y, &vert[vq].z);
			vq++;
		}else if (strncmp(p, "f", 1) == 0) {
			if (strstr(p,"//")) {
				sscanf(
					p,
					"f %u//%u %u//%u %u//%u",
					&poly[pq].v1,
					&poly[pq].n1,
					&poly[pq].v2,
					&poly[pq].n2,
					&poly[pq].v3,
					&poly[pq].n3
				);
				poly[pq].v1 -= 1;
				poly[pq].t1 = 0;
				poly[pq].n1 -= 1;
				poly[pq].v2 -= 1;
				poly[pq].t2 = 1;
				poly[pq].n2 -= 1;
				poly[pq].v3 -= 1;
				poly[pq].t3 = 1;
				poly[pq].n3 -= 1;
			}else{
				sscanf(
					p,
					"f %u/%u/%u %u/%u/%u %u/%u/%u",
					&poly[pq].v1,
					&poly[pq].t1,
					&poly[pq].n1,
					&poly[pq].v2,
					&poly[pq].t2,
					&poly[pq].n2,
					&poly[pq].v3,
					&poly[pq].t3,
					&poly[pq].n3
				);
				poly[pq].v1 -= 1;
				poly[pq].t1 -= 1;
				poly[pq].n1 -= 1;
				poly[pq].v2 -= 1;
				poly[pq].t2 -= 1;
				poly[pq].n2 -= 1;
				poly[pq].v3 -= 1;
				poly[pq].t3 -= 1;
				poly[pq].n3 -= 1;
			}
			poly[pq].m = m;
			pq++;
		}else if (strncmp(p, "usemtl", 6) == 0) {
			sscanf(p,"usemtl %s",tmp);
			mat = mat_find(tmp);
			if (!mat)
				mat = mat_create();
			m = mesh_create_material(mat);
			array_push_ptr(mdl->meshes,m);
		}

		p = strchr(p,'\n');
		if (!p)
			break;
		p++;
	}

	/* stage 2, make a rosethorn model out of it */
	if (!nq) {
		for (i=0; i<pq; i++) {
			mesh_push_polypoint(poly[i].m,&vert[poly[i].v1],&tex[poly[i].t1]);
			mesh_push_polypoint(poly[i].m,&vert[poly[i].v2],&tex[poly[i].t2]);
			mesh_push_polypoint(poly[i].m,&vert[poly[i].v3],&tex[poly[i].t3]);
		}
		for (i=0; i<mdl->meshes->length; i++) {
			m = ((mesh_t**)(mdl->meshes->data))[i];
			mesh_calc_normals(m);
		}
	}else{
		for (i=0; i<pq; i++) {
			mesh_push_polypoint_n(poly[i].m,&vert[poly[i].v1],&norm[poly[i].n1],&tex[poly[i].t1]);
			mesh_push_polypoint_n(poly[i].m,&vert[poly[i].v2],&norm[poly[i].n2],&tex[poly[i].t2]);
			mesh_push_polypoint_n(poly[i].m,&vert[poly[i].v3],&norm[poly[i].n3],&tex[poly[i].t3]);
		}
	}

	return mdl;
}
